<?php
// +----------------------------------------------------------------------
// | ZengCMS [ 火火 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2018 http://zengcms.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 火火 <zengcms@qq.com>
// +----------------------------------------------------------------------

// +----------------------------------------------------------------------
// | 自定义自动抛出异常处理类，重写Handle的render方法，实现自定义异常消息
// +----------------------------------------------------------------------
namespace app\common\exception;

use Throwable;
use think\Response;
use think\facade\Log;
use think\facade\Env;
use think\exception\Handle;
use app\api\lib\DataHandle;
use think\exception\HttpException;
use think\exception\ValidateException;
use app\api\lib\exception\MissException;
use app\api\lib\exception\HttpException as HttpExceptions;

class ExceptionHandle extends Handle
{
    use DataHandle;
    // 异常代码
    private $code = 10500;
    // 异常消息内容
    private $message = 'Internal Server Error';
    // http状态码
    private $httpCode = 500;
    // 是否把真实"服务端内部错误"异常消息内容给客户端
    private $shouldToClient = true;
    /**
     * render方法
     * @param [type] $request
     * @param Throwable $e
     * @return Response
     */
    public function render($request, Throwable $e): Response
    {
        /* // 参数验证错误
        if ($e instanceof ValidateException) {
            return json($e->getError(), 422);
        }
        // 请求异常
        if ($e instanceof HttpException && $request->isAjax()) {
            return response($e->getMessage(), $e->getStatusCode());
        }
        // 其他错误交给系统处理
        return parent::render($request, $e); */
        // 判断是自定义的手动抛出异常，还是thinkphp内置异常类抛出的。
        if ($e instanceof MissException) {
            // 如果是自定义异常，则控制http状态码，
            // 不需要记录日志因为这些通常是因为客户端传递参数错误
            // 或者是用户请求造成的异常不应当记录日志
            // http状态码
            $this->httpCode = $e->httpCode;
            // 异常消息内容
            $this->message = $e->message;
            // 异常代码
            $this->code = $e->code;
        } elseif ($e instanceof HttpExceptions) {
            // http状态码
            $this->httpCode = $e->getHttpCode();
            // 异常消息内容
            $this->message = $e->getMessage();
            // 异常代码
            $this->code = $e->getCode();
        } else { // thinkphp内置异常类抛出的(全局thinkphp抛出)
            // 调试状态下需要显示TP默认的异常页面，因为TP的默认页面很容易看出问题
            $module = app('http')->getName();
            if($module == 'admin') {
                if(!Env::get('APP_DEBUG',false) && (request()->isAjax() || request()->isPost())){
                    // 参数验证错误
                    if ($e instanceof ValidateException) {
                        return json(['code'=>0,'msg'=>$e->getError(),'url'=>'']);
                    }
                    // 请求异常
                    if ($e instanceof HttpException && $request->isAjax()) {
                        return json(['code'=>0,'msg'=>$e->getMessage(),'url'=>'']);
                    }
                    if($e->getMessage()){
                        return json(['code'=>0,'msg'=>$e->getMessage(),'url'=>'']);
                    }
                    return $e->getResponse();
                }else{
                    // 参数验证错误
                    if ($e instanceof ValidateException) {
                        return json($e->getError(), 422);
                    }
                    // 请求异常
                    if ($e instanceof HttpException && $request->isAjax()) {
                        return response($e->getMessage(), $e->getStatusCode());
                    }
                    // 其他错误交给系统处理
                    return parent::render($request, $e);
                }
            } elseif ($module == "") {
                // 参数验证错误
                if ($e instanceof ValidateException) {
                    return json($e->getError(), 422);
                }
                // 请求异常
                if ($e instanceof HttpException && $request->isAjax()) {
                    return response($e->getMessage(), $e->getStatusCode());
                }
                // 其他错误交给系统处理
                return parent::render($request, $e);
            } elseif ($this->shouldToClient) { //判断是否把真实"服务端内部错误"异常消息内容给客户端，是
                // 异常消息内容
                $this->message = 'Error message：' . $e->getMessage() . '；' . 
                'Error file：' . $e->getFile() . '；' . 
                'Error line：' . $e->getLine();
                // 异常代码
                $this->code = $e->getCode(); 
            }
            // 记录日志
            Log::record($e->getMessage(), 'error');
        }
        // 返回数据
        $result_data = [
            // 异常代码
            'code'        => $this->code, 
            // 异常消息内容
            'message'     => $this->message,
            // 请求url
            'request_url' => request()->url()
        ];
        return $this->returnData($result_data, $this->httpCode);
    }
}
